#include "TcpServer.h"
#include "Logger.h"

void TcpServer::DefaultConnection(const TcpConnectionPtr&) {}
void TcpServer::DefaultMessage(const TcpConnectionPtr&) {}

TcpServer::TcpServer(EventLoop* loop, InetAddress address, std::string name)
    : loop_(loop),
      ip_port_(address.IpPort()),
      name_(name),
      acceptor_(new Acceptor(loop_, address)),
      thread_pool_(new LoopThreadPool(loop_)),
      next_conn_id(1),
      started_(0) {
    LOG_INFO("ip and port:%s", ip_port_.c_str());
    LOG_INFO("listenfd:%d", acceptor_->Fd());
    acceptor_->SetConnectionCallback(
        std::bind(&TcpServer::NewConnection, this, std::placeholders::_1, std::placeholders::_2));
}

void TcpServer::SetConnectionCallback(const ConnectionCallback& cb) {
    connection_callback_ = cb;
}
void TcpServer::SetMessageCallback(const MessageCallback& cb) {
    message_callback_ = cb;
}

void TcpServer::SetThreadNum(int num) {
    thread_pool_->SetThreadNum(num);
}

void TcpServer::start() {
    // 防止start多次
    if (started_++ == 0) {
        thread_pool_->start();
        loop_->RunInLoop(std::bind(&Acceptor::Listen, acceptor_.get()));
    }
}

// About connection:
void TcpServer::NewConnection(int connfd, InetAddress peer_addr) {
    // 根据轮询算法选择并分发给一个subloop
    EventLoop* ioloop = thread_pool_->GetNextLoop();
    // connfd -》 channel -》 subloop
    // 在MainLoop线程中执行：ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
    char buf[64] = {0};
    snprintf(buf, sizeof(buf), "%s#%d", ip_port_.c_str(), next_conn_id);
    next_conn_id++;
    std::string conn_name = name_ + buf;
    LOG_INFO("Have a new connection %s", conn_name.c_str());
    sockaddr_in local;
    bzero(&local, sizeof(local));
    socklen_t addrlen = sizeof(local);
    getsockname(connfd, (sockaddr*)&local, &addrlen);
    InetAddress local_addr(local);

    TcpConnectionPtr conn(new TcpConnection(ioloop, conn_name, connfd, peer_addr, local_addr));

    connections_[conn_name] = conn;

    conn->SetConnectionCallback(connection_callback_);
    conn->SetMessageCallback(message_callback_);
    conn->SetWriteCompleteCallback(write_complete_callback_);
    conn->SetCloseCallback(std::bind(&TcpServer::RemoveConnection, this, std::placeholders::_1));

    ioloop->RunInLoop(std::bind(&TcpConnection::ConnectEstablished, conn));
}

void TcpServer::RemoveConnection(const TcpConnectionPtr& conn) {
    loop_->RunInLoop(std::bind(&TcpServer::RemoveConnectionInLoop, this, conn));
}

void TcpServer::RemoveConnectionInLoop(const TcpConnectionPtr& conn) {
    connections_.erase(conn->Name());
    EventLoop* ioLoop = conn->Loop();
    ioLoop->QueueInLoop(std::bind(&TcpConnection::ConnectDestroyed, conn));
}

TcpServer::~TcpServer() {
    for (auto& item : connections_) {
        TcpConnectionPtr conn(item.second);
        item.second.reset();  // 把原始的智能指针复位 让栈空间的TcpConnectionPtr conn指向该对象 当conn出了其作用域
                              // 即可释放智能指针指向的对象
        // 销毁连接
        conn->Loop()->RunInLoop(std::bind(&TcpConnection::ConnectDestroyed, conn));
    }
}
